home *** CD-ROM | disk | FTP | other *** search
/ Disc to the Future 2 / Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin / MAC / TOOLS_&_ / I-PATCH_ / CODEPUNC / CODEPUNC.H_T
Text File  |  1991-10-20  |  13KB  |  175 lines

  1. ------------
  2. I-Patch¬ 1.0                                                                                                Copyright ⌐1991 Senseless (ó<) Software
  3. ------------
  4. by Steve Mariotti
  5.  
  6.                                                                                                     CODEPUNCH Tutorial
  7.  
  8.     I decided to write up a little tutorial that explains the CODEPUNCH command since it's the most complicated and most powerful I-Patch¬ command.  It requires a bit of preparation to use, whereas most I-Patch¬ commands require either some hex data or a resource of some kind or other.
  9.     For CODEPUNCH, you will need information about the segment of code that you're punching into, a CODE resource for the CODEPUNCH code to call, and the corresponding info for the script.
  10.     The function of CODEPUNCH is to place a 26 byte segment of code into an existing CODE resource (or any resource that has executable code in it) that has the function of loading another specified resource, calling it with a JSR, and then resuming  code execution immediately following the 'punched-in' code.  This allows the script writer to have any application execute additional code not originally in the application without disturbing the original application at all.
  11.     As you will see in this example, some code will be added to the Sample App (in the Sample App folder included in the I-Patch¬ package) that will load up a sound resource and play that sound when the Sample App starts up.  This function was not included in the original application, but will be 'punched-in' by the script.
  12.  
  13.     In preparation for the CODEPUNCH, we need a debugger such as MacsBug or (my favorite) TMON Professional.
  14.  
  15.     A good place to punch in my code is at the very beginning of the application where it does its initialization.  There's space here to put in my 26 bytes of CODEPUNCH code.  The code that is 'punched-in' is the following:
  16.  
  17.     CLR.L                                    -(SP)                                                            ;  save 4 bytes on stack for res handle
  18.     MOVE.L                             #$00000000, -(SP)                ;  push the ResType to load
  19.     MOVE.W                            #$0000, -(SP)                                ;  push the ResID to load
  20.     _GetResource                                                                                     ;  get the resource from the res file
  21.     MOVEA.L                            (SP), A0                                              ;  put the handle to the resource in reg A0
  22.     _HLock                                                                                                         ;  lock the resource
  23.     MOVEA.L                            (A0), A1                                                ;  put the address of the resource data in A1
  24.     JSR                                            (A1)                                                            ;  call the loaded resource's code
  25.     _HUnlock                                                                                                    ;  Unlock the resource
  26.     _ReleaseResource                                                                        ;  release the memory occupied by it
  27.  
  28.     This occupies 26 bytes of space, and thus I must find 26 bytes of code that are 'safe' to punch in over (code that can be included in the loaded code resource and will execute
  29. there safely).  This requires some examination of the object code of the application that will be 'punched-into', and the debugger is great for this.
  30.  
  31.     Since I want to look at the application's initialization code, I set my debugger up to do a trap intercept at _InitGraf since this is commonly the first trap executed by any application as part of its initialization.  I then run the Sample App and let it break.  Examining the code around the program counter after the break reveals the following segment of code:
  32.  
  33. 005CB51E:'CODE'¿$0002─$125E+$01EE PEA     `FFEE(A5)
  34. 005CB522:'CODE'¿$0002─$125E+$01F2 _InitGraf
  35. 005CB524:'CODE'¿$0002─$125E+$01F4 _InitWindows
  36. 005CB526:'CODE'¿$0002─$125E+$01F6 _InitFonts
  37. 005CB528:'CODE'¿$0002─$125E+$01F8 _InitMenus
  38. 005CB52A:'CODE'¿$0002─$125E+$01FA _TEInit
  39. 005CB52C:'CODE'¿$0002─$125E+$01FC CLR.L   -(A7)
  40. 005CB52E:'CODE'¿$0002─$125E+$01FE _InitDialogs
  41. 005CB530:'CODE'¿$0002─$125E+$0200 _InitCursor
  42. 005CB532:'CODE'¿$0002─$125E+$0202 _MoreMasters
  43. 005CB534:'CODE'¿$0002─$125E+$0204 _MoreMasters
  44. 005CB536:'CODE'¿$0002─$125E+$0206 _MoreMasters
  45. 005CB538:'CODE'¿$0002─$125E+$0208 _MoreMasters
  46. 005CB53A:'CODE'¿$0002─$125E+$020A _MoreMasters
  47. 005CB53C:'CODE'¿$0002─$125E+$020C _MoreMasters
  48. 005CB53E:'CODE'¿$0002─$125E+$020E CLR.B   `FFFE(A5)
  49. 005CB542:'CODE'¿$0002─$125E+$0212 RTS
  50.  
  51.     I can see that there is room to put my 26 bytes of CODEPUNCH code here, and I choose to put it immediately following the _InitGraf trap.  When I-Patch¬ codes the codepunch, it will place it's codepunch code over the top of _InitWindows, _InitFonts, etc.. all the way over all of the calls to _MoreMasters and right up to the CLR.B instruction.  It is not the case that the last byte of the 26 cuts an existing instruction in half (the _MoreMasters trap instruction is only 2 bytes, but another instruction, such as a MOVE.L immediate for example, could be several words long).  If it is the case that an existing instruction is only partially overwritten by the last bytes of the CODEPUNCH code, there will be a garbage instruction immediately following the last instruction of the CODEPUNCH code (the _ReleaseResource trap).  When this happens, it is necessary to put one or more 'NOP' (No OPeration) instructions there to overwrite the rest of the clobbered instruction.  This ensures that program execution will continue after the CODEPUNCH code without encountering illegal instructions.  There is a provision in the calling syntax of the CODEPUNCH script command to tell I-Patch¬ to write a number of NOP instructions immediately after writing the CODEPUNCH code into the application code.  Since there are no clobbered instructions in this example, this won't be necessary--the 26 bytes fit perfectly.
  52.  
  53. After the CODEPUNCH command puts its code into this sequence of instructions, they look like this:
  54.  
  55. 00596FC6:'CODE'¿$0002─$12BC+$01EE PEA     `FFEE(A5)
  56. 00596FCA:'CODE'¿$0002─$12BC+$01F2 _InitGraf
  57. 00596FCC:'CODE'¿$0002─$12BC+$01F4 CLR.L   -(A7)  ; <-- beginning of punched code
  58. 00596FCE:'CODE'¿$0002─$12BC+$01F6 MOVE.L  #$706E6368,-(A7)                   ;'pnch'
  59. 00596FD4:'CODE'¿$0002─$12BC+$01FC MOVE.W  #$04D2,-(A7)                          ;#1234
  60. 00596FD8:'CODE'¿$0002─$12BC+$0200 _GetResource
  61. 00596FDA:'CODE'¿$0002─$12BC+$0202 MOVEA.L (A7),A0
  62. 00596FDC:'CODE'¿$0002─$12BC+$0204 _HLock
  63. 00596FDE:'CODE'¿$0002─$12BC+$0206 MOVEA.L (A0),A1
  64. 00596FE0:'CODE'¿$0002─$12BC+$0208 JSR     (A1)
  65. 00596FE2:'CODE'¿$0002─$12BC+$020A _HUnlock
  66. 00596FE4:'CODE'¿$0002─$12BC+$020C _ReleaseResource ; <-- last punched instr.
  67. 00596FE6:'CODE'¿$0002─$12BC+$020E CLR.B   `FFFE(A5)
  68. 00596FEA:'CODE'¿$0002─$12BC+$0212 RTS
  69.  
  70. As you can see, control passes immediately to the CLR.B instruction.  What was clobbered by this code is the rest of the initialization: the _InitWindows, _InitFonts, all the way through all of the _MoreMaster's calls.  Since this code no longer exists and will not be executed, it will have to be included in the loaded code resource.  Examining the punched in code indicates that the resource that the _GetResource trap will load is a resource of type 'pnch' and resource ID #1234.  This is information that I supplied the CODEPUNCH command inside the I-Patch¬ script.  These could be any resource type and any res ID that I wanted, so long as I included that resource as part of the I-Patch¬ script.
  71.  
  72.     But, I'm getting ahead of myself here.  Back to the sequence of operations.  The first thing that the user must do is look at the application's code for the place to overwrite with the CODEPUNCH code.  Examination of the first dump above indicates that at hex offset $01F4 from the beginning of CODE resource ID#2 there is a good place to put the punched code.  I write down that info.. (CODE ID #2, offset $01F4) because I'll need it later when I'm writing the script itself.
  73.  
  74.     Next, it's my job to write a CODE resource that will be loaded.  I used THINK C to compile my code.  The source file is included in the I-Patch¬ package.  It's my responsibility to remember what code was overwritten and include it in my CODE resource somewhere.  Since the initialization code for the Sample App was overwritten, I will include this at the beginning of my code resource (which will be of type 'pnch' and ID #1234 as we now know).  
  75.     The code I wrote looks like this:
  76.  
  77. void main()
  78. {
  79.     Handle        myHand;  /* a temporary handle for my punched-in code */
  80.     
  81.     
  82.     /* This the overwrite code--that is, the code that was overwritten by the CODEPUNCH
  83.         code when I-Patch executed the CODEPUNCH operation.  The code that it replaced
  84.         the application's old code with has the function of loading and executing a
  85.         resource.  This is that resource, and since some code was overwritten, I will
  86.         have to include that code in this resource so that it DOES get executed.
  87.     */
  88.     
  89.     /* this is the code that was overwritten by the 'punched-in' code */
  90.                 InitWindows();
  91.                 InitFonts();
  92.                 InitMenus();
  93.                 TEInit();
  94.                 InitDialogs(NULL);
  95.                 InitCursor();
  96.                 MoreMasters();
  97.                 MoreMasters();
  98.                 MoreMasters();
  99.                 MoreMasters();
  100.                 MoreMasters();
  101.                 MoreMasters();
  102.     /* now that the application's original code has been executed, */
  103.     /* I can do what I want to do */
  104.     
  105. /* the following code is the code that I want to execute -- my own code.  It can be 
  106.      anything I choose */
  107. /* I choose to load up a sound resource and play it before exiting my code resource and allowing the application to continue */
  108.  
  109.               myHand = GetResource('snd ', 1234);        /* load up 'snd ' resource ID 1234 */
  110.                 SndPlay(NULL, myHand, FALSE);            /* play the sound resource */
  111.     
  112. /* that's all I want this CODE resource to do */
  113. }
  114.  
  115.     So I compile this code and save it as a code resource.  I used THINK C with the Custom Headers option on so that THINK C won't put it's code resource header at the beginning of the code resource.  A matter of preference, I guess.
  116.  
  117.     Now I'm ready to write the I-Patch¬ script to take advantage of the information I've gathered and the resource I just wrote.  I load up I-Patch¬ and start typing:
  118.  
  119. * This is a script to use the CODEPUNCH command
  120. * to add into the Sample App some code that plays a sound
  121.  
  122. * I gotta prompt the user to select the Sample App so I can patch it
  123. MESSAGE
  124. "Please select a COPY of the Sample App"
  125.  
  126. * Now I need to actually open up the application
  127. SELECTFILE
  128. 1
  129. 'APPL'
  130.  
  131. * Ok, it's open, now I'm ready to do the CODEPUNCH
  132. * I want to punch into CODE resource #2 at offset
  133. * $01F4 from the beginning .  I also want to tell the
  134. * CODEPUNCH command that the punched-in code 
  135. * should load a resource of type 'pnch' with ID#1234.
  136. * This is the code resource that I compiled earlier.
  137. CODEPUNCH
  138. 'CODE'
  139. 2
  140. $1f4
  141. 0
  142. 'pnch'
  143. 1234
  144.  
  145. * Since my 'pnch' resource loads up a sound that is
  146. * not already in the Sample App, I need to add this
  147. * resource myself.  I've already got a sound resource
  148. * made and its ID is 1234 as well.  I need to
  149. * Add the 'snd ' resource to the App
  150. ADD
  151. 'snd '
  152. 1234
  153. 'snd '
  154. 1234
  155.  
  156. * That's the last thing I need to do.. all done
  157. END
  158.  
  159. There, that's the whole script.  Of course 2 things are missing from this script file.  The script executes the right commands in the right order, but the script must also have the resources that are referenced in the script text loaded into it.  I can do this by loading up ResEdit, opening up the files that contain the resources and use the clipboard to copy and paste them, or I can use the I-Patch¬ menu command Add Resource that's on the Script menu to add them from within I-Patch.  I will illustrate both methods.
  160.  
  161.     THINK C compiled my 'pnch' resource to a file.  I load up ResEdit and open this file.  Inside is a resource of type 'pnch' with ID 1234 as I told THINK C.  I then select it in the list of 'pnch' resources and do a Copy (Command-C).  It's now on the clipboard.
  162.     Next, I load up I-Patch¬, open the above I-Patch¬ script file, I click in the Resources Box to select it, and then I do a Paste (Command-V).  The resource on the clipboard is now pasted into the I-Patch¬ script.  Of course, the resource ID number is wrong since the clipboard doesn't maintain resource ID's--only types.  So I can use the Get Info menu command to change the ID to 1234 like the script text requires.
  163.     Now I do the same set of operations on the file that contains the 'snd ' resource to add that to the script.
  164.  
  165.     The other method is to use the Get Resource menu command within I-Patch¬.  This is a much easier way to do it, but clipboard compatibility was provided for those who prefer to work with ResEdit.
  166.     Ok, so within I-Patch¬, I've just typed the script.  I can hit Command-R or choose Add Resource from the Script menu.  This command will offer a file selection dialog and let you choose the resource file that contains the resource that you want to add.  After you open the file, you will be confronted by a list of resource types and resources.  Find the one you want and hit the OK button.  It will automatically be loaded into the I-Patch¬ script's Resources Box with the correct type and ID.  Do this for both the 'pnch' code resource and the sound resource.
  167.  
  168.     That's it.  Now the script is complete.  This would be a good time to save.
  169.  
  170.     If you execute this script, it will patch the Sample App as required.
  171.  
  172.     A completed script was included in the CODEPUNCH Tutorial Folder that is essentially the same thing as what was generated above.  The sound resource and the compiled code resource are also in this folder so that you may follow the above steps to generate your own version of the script.  I recommend doing it yourself to get the hang of it.
  173.  
  174.     Make sure to make a copy of the Sample App before applying the patch, just in case there might be an error in the script.  It's never a good idea to apply patches of any kind to the original and only copy of something.
  175.